
//package java_cup;

//import java.util.Dictionary;
//import java.util.Stack;



using System.IO.IsolatedStorage;

/**
 * This class represents a state in the LALR viable prefix recognition machine.
 * A state consists of an LALR item set and a set of transitions to other states
 * under Vt_ and non-Vt_ EmitSymbols. Each state represents a potential
 * configuration of the CUPParser. If the item set of a state includes an item such
 * as:
 * 
 * <pre>
 *    [A ::= B * C d E , {a,b,c}]
 * </pre>
 * 
 * this indicates that when the CUPParser is in this state it is currently looking
 * for an A of the given form, has already seen the B, and would expect to see
 * an a, b, or c after this sequence is complete. Note that the CUPParser is
 * normally looking for several things at once (represented by several ItemSet).
 * In our example above, the state would also include ItemSet such as:
 * 
 * <pre>
 *    [C ::= * X e Z, {d}]
 *    [X ::= * f, {e}]
 * </pre>
 * 
 * to indicate that it was currently looking for a C followed by a d (which
 * would be reduced into a C, matching the first SymbolDraft in our production
 * above), and the Vt_ f followed by e.
 * <productionDraft>
 *
 * At runtime, the CUPParser uses a viable prefix recognition machine made up of
 * these states to parse. The CUPParser has two operations, Shift and reduce. In a
 * Shift, it consumes one TheSymbolDraft and makes a transition to a new state. This
 * corresponds to "moving the dot past" a Vt_ in one or more ItemSet in the
 * state (these new shifted ItemSet will then be found in the state at the end of
 * the transition). For a reduce operation, the CUPParser is signifying that it is
 * recognizing the RHS of some production. To do this it first "backs up" by
 * popping a stack of previously saved states. It pops off the same Count of
 * states as are found in the RHS of the production. This leaves the machine in
 * the same state is was in when the CUPParser first attempted to find the RHS.
 * From this state it makes a transition based on the non-Vt_ on the LHS of
 * the production. This corresponds to placing the parse in a configuration
 * equivalent to having replaced AllVns the EmitSymbols from the the input
 * corresponding to the RHS with the SymbolDraft on the LHS.
 *
 * @see java_cup.lalr_item
 * @see java_cup.lalr_item_set
 * @see java_cup.lalr_transition
 * @version last updated: 7/3/96
 * @author Frank Flannery
 * 
 */
public class LALRState {
    /*-----------------------------------------------------------*/
    /*--- Constructor(s) ----------------------------------------*/
    /*-----------------------------------------------------------*/

    /**
     * Constructor for building a state from a set of ItemSet.
     * 
     * @param ItemSet the set of ItemSet that makes up this state.
     */
    public LALRState(LALRItemSet items) /*throws internal_error*/ {
        /* don't allow null or duplicate item sets */
        if (items == null)
            throw new InternalError("Attempt to construct an LALR state from a null item set");

        if (FindState(items) != null)
            throw new InternalError("Attempt to construct a duplicate LALR state");

        /* assign a unique index */
        _index = next_index++;

        /* store the ItemSet */
        _itemSet = items;

        /* TryAdd to the global collection, keyed with its item set */
        _itemSet2State.Add(items, this);
    }

    /*-----------------------------------------------------------*/
    /*--- (Access to) Static (Class) Variables ------------------*/
    /*-----------------------------------------------------------*/

    /** Collection of AllVns states. */
    public static Dictionary<LALRItemSet, LALRState> _itemSet2State = new();

    /** Collection of AllVns states. */
    public static IEnumerable<LALRState> AllStates() {
        return _itemSet2State.Values;
    }

    // Hm Added clear to clear AllVns static fields
    public static void Clear() {
        _itemSet2State.Clear();
        _kernelSet2State.Clear();
    }

    /* . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . */

    /** Indicate total Count of states there are. */
    public static int Count => _itemSet2State.Count;

    /* . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . */

    /**
     * Hash table to find states by their kernels (i.e, the original, unclosed, set
     * of ItemSet -- which uniquely define the state). This table stores state objects
     * using (a copy of) their toKernel item sets as keys.
     */
    public static Dictionary<LALRItemSet, LALRState> _kernelSet2State = new();

    /* . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . */

    /**
     * Find and return state with a given a toKernel item set (or null if not found).
     * The toKernel item set is the subset of ItemSet that were used to originally
     * create the state. These ItemSet are formed by "shifting the dot" within ItemSet
     * of other states that have a transition to this one. The remaining elements of
     * this state's item set are added during closure.
     * 
     * @param ItemSet the toKernel set of the state we are looking for.
     */
    public LALRState FindState(LALRItemSet items) {
        if (items == null)
            return null;
        else
            return _itemSet2State[items];
    }

    /* . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . */

    /** Static counter for assigning unique state indexes. */
    public static int next_index;

    /*-----------------------------------------------------------*/
    /*--- (Access to) Instance Variables ------------------------*/
    /*-----------------------------------------------------------*/

    /** The item set for this state. */
    public LALRItemSet _itemSet;

    /** The item set for this state. */
    public LALRItemSet ItemSet => _itemSet;

    /* . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . */

    /** List of transitions @out of this state. */
    public LALRTransition _transition = null;

    /** List of transitions @out of this state. */
    public LALRTransition Transition => _transition;

    /* . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . */

    /** Index of this state in the parse tables */
    public int _index;

    /** Index of this state in the parse tables */
    public int Index => _index;

    /*-----------------------------------------------------------*/
    /*--- Static Methods ----------------------------------------*/
    /*-----------------------------------------------------------*/

    /**
     * Helper routine for debugging -- produces a dump of the given state onto
     * System.@out.
     */
    public static void DumpState(LALRState state) /*throws internal_error*/ {
        if (state == null) {
            System.Console.WriteLine("NULL LALRState");
            return;
        }

        System.Console.WriteLine("LALRState [" + state.Index + "] {");
        foreach (var item in state.ItemSet) {
            System.Console.Write("  [");
            System.Console.Write(item.ProductionDraft.lhs.TheSymbolDraft.Name);
            System.Console.Write(" ::= ");
            for (int i = 0; i < item.ProductionDraft.rhsLength; i++) {
                if (i == item.DotPosition)
                    System.Console.Write("\u00B7 ");
                var part = item.ProductionDraft.rhs(i);
                if (part.IsAction)
                    System.Console.Write("{actionPart} ");
                else
                    System.Console.Write(((SymbolPart)part).TheSymbolDraft.Name + " ");
            }
            if (item.dotAtEnd)
                System.Console.Write("\u00B7 ");
            System.Console.WriteLine("]");
        }
        System.Console.WriteLine("}");
    }

    /* . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . */

    /**
     * Propagate lookahead sets through the constructed viable prefix recognizer.
     * When the machine is constructed, each item that results in the creation of
     * another such that its lookahead is included in the other's will have a
     * propagate link set up for it. This allows additions to the lookahead of one
     * item to be included in other ItemSet that it was used to directly or indirectly
     * create.
     */
    public static void PropagateAllLookaheads() /*throws internal_error*/ {
        /* iterate across AllVns states */
        foreach (var state in AllStates()) { state.PropagateLookaheads(); }
    }

    /*-----------------------------------------------------------*/
    /*--- General Methods ---------------------------------------*/
    /*-----------------------------------------------------------*/

    /**
     * Add a transition @out of this state to another.
     * 
     * @param on_sym the SymbolDraft the transition is under.
     * @param to_st  the state the transition goes to.
     */
    public void AddTransition(SymbolDraft onSym, LALRState toSt) /*throws internal_error*/ {
        /* create a new transition object and put it in our list */
        this._transition = new LALRTransition(onSym, toSt, this._transition);
    }

    /* . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . */

    /**
     * Build an LALR viable prefix recognition machine given a start production.
     * This method operates by first building a start state from the start
     * production (based on a single item with the dot at the beginning and EOF as
     * expected lookahead). Then for each state it attempts to extend the machine by
     * creating transitions out of the state to new or existing states. When
     * considering extension from a state we make a transition on each SymbolDraft that
     * appears before the dot in some item. For example, if we have the ItemSet:
     * 
     * <pre>
     *    [A ::= a b * X c, {d,e}]
     *    [B ::= a b * X d, {a,b}]
     * </pre>
     * 
     * in some state, then we would be making a transition under X to a new state.
     * This new state would be formed by a "toKernel" of ItemSet corresponding to moving
     * the dot past the X. In this case:
     * 
     * <pre>
     *    [A ::= a b X * c, {d,e}]
     *    [B ::= a b X * Y, {a,b}]
     * </pre>
     * 
     * The full state would then be formed by "closing" this toKernel set of ItemSet so
     * that it included ItemSet that represented AllProdctions of things the CUPParser was
     * now looking for. In this case we would ItemSet corresponding to AllProdctions of
     * Y, since various forms of Y are expected next when in this state (see
     * lalr_item_set.compute_closure() for details on closure).
     * <productionDraft>
     *
     * The process of building the viable prefix recognizer terminates when no new
     * states can be added. However, in order to build a smaller Count of states
     * (i.e., corresponding to LALR rather than canonical LR) the state building
     * process does not maintain full loookaheads in AllVns ItemSet. Consequently, after
     * the machine is built, we go back and propagate lookaheads through the
     * constructed machine using a call to propagate_all_lookaheads(). This makes
     * use of propagation links constructed during the closure and transition
     * process.
     *
     * @param firstProduction the start production of the grammar
     * @see java_cup.lalr_item_set#compute_closure
     * @see java_cup.LALRState#propagate_all_lookaheads
     */

    public static LALRState BuildMachine(ProductionDraft firstProduction)
        /*throws internal_error*/ {
        Queue<LALRState> queue = new();
        LALRState firstState;
        {
            /* sanity check */
            if (firstProduction == null)
                throw new InternalError("Attempt to build viable prefix recognizer using a null production");

            /* build item with dot at front of start production and EOF lookahead */
            LALRItemSet firstItemSet = new LALRItemSet();
            var firstItem = new LALRItem(firstProduction);
            firstItem.LookAheads.Add(Vt.EOF);
            firstItemSet.AddMerge(firstItem);
            /* create copy the itemSet to form the toKernel */
            var kernelSet = new LALRItemSet(firstItemSet);
            /* create the closure from that item set */
            firstItemSet.computeClosure();
            /* build a state out of that itemSet and put it in our queue */
            firstState = new LALRState(firstItemSet);
            queue.Enqueue(firstState);
            /* enter the state using the toKernel as the key */
            _kernelSet2State.Add(kernelSet, firstState);
        }
        /* continue looking at new states until we have no more work to do */
        while (queue.Count > 0) {
            /* remove a state from the work set */
            var subject = queue.Dequeue();

            /* gather up AllVns the EmitSymbols that appear before dots */
            var symbols = new SymbolSet();
            foreach (var item in subject.ItemSet) {
                /* TryAdd the SymbolDraft before the dot (if any) to our collection */
                var symbol = item.SymbolAfterDot;
                if (symbol != null) { symbols.TryAdd(symbol); }
            }

            /* now create a transition @out for each individual SymbolDraft */
            foreach (var symbol in symbols) {
                /* will be keeping the set of ItemSet with propagate links */
                var shiftedItems = new LALRItemSet();
                // gather up shifted versions of AllVns the ItemSet
                // that have this SymbolDraft before the dot
                var toItemSet = new LALRItemSet();
                foreach (var item in subject.ItemSet) {
                    /* if this is the SymbolDraft we are working on now, TryAdd to set */
                    if (symbol.Equals(item.SymbolAfterDot)) {
                        /* TryAdd to the toKernel of the new state */
                        toItemSet.AddMerge(item.Shift());
                        /* remember that item has propagate link to it */
                        shiftedItems.AddMerge(item);
                    }
                }

                /* use new ItemSet as state toKernel */
                var toKernel = new LALRItemSet(toItemSet);
                /* have we seen this one already? */
                var toState = _kernelSet2State[toKernel];

                /* if we haven't, build a new state out of the item set */
                if (toState == null) {
                    /* compute closure of the toKernel for the full item set */
                    toItemSet.computeClosure();

                    /* build the new state */
                    toState = new LALRState(toItemSet);
                    /* TryAdd the new state to our work set */
                    queue.Enqueue(toState);
                    /* put it in our toKernel table */
                    _kernelSet2State.Add(toKernel, toState);
                }
                /* otherwise relink propagation to ItemSet in existing state */
                else {
                    /* walk through the ItemSet that have links to the new state */
                    foreach (var item in shiftedItems) {
                        /* look at each propagate link @out of that item */
                        for (int i = 0; i < item.PropagateItems.Count; i++) {
                            /* pull out item linked to in the new state */
                            LALRItem itemee = item.PropagateItems[i];

                            /* find corresponding item in the existing state */
                            LALRItem existing = toState.ItemSet.Find(itemee);
                            /* fix up the item so it points to the existing set */
                            if (existing != null) {
                                //item.propagate_items().setElementAt(existing, i);
                                item.PropagateItems[i] = existing;
                            }
                        }
                    }
                }

                /* TryAdd a transition from current state to that state */
                subject.AddTransition(symbol, toState);
            }
        }

        /* AllVns done building states */

        /* propagate complete lookahead sets throughout the states */
        PropagateAllLookaheads();

        return firstState;
    }

    /* . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . */

    /**
     * Propagate lookahead sets @out of this state. This recursively propagates to
     * AllVns ItemSet that have propagation links from some item in this state.
     */
    public void PropagateLookaheads() /*throws internal_error*/ {
        /* recursively propagate @out from each item in the state */
        foreach (var item in this.ItemSet) { item.PropagateLookAheads(null); }
    }

    /* . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . */

    /**
     * Fill in the parse table entries for this state. There are two parse tables
     * that encode the viable prefix recognition machine, an actionPart table and a
     * reduce-goto table. The rows in each table correspond to states of the
     * machine. The columns of the actionPart table are indexed by Vt_ EmitSymbols and
     * correspond to either transitions @out of the state (Shift entries) or
     * reductions from the state to some previous state saved on the stack (reduce
     * entries). AllVns entries in the actionPart table that are not shifts or reduces,
     * represent errors. The reduce-goto table is indexed by non terminals and
     * represents transitions @out of a state on that non-Vt_.
     * <productionDraft>
     * Conflicts occur if more than one actionPart needs to go in one entry of the
     * actionPart table (this cannot happen with the reduce-goto table). Conflicts are
     * resolved by always shifting for Shift/reduce conflicts and choosing the
     * lowest numbered production (hence the one that appeared first in the
     * specification) in reduce/reduce conflicts. AllVns conflicts are reported and if
     * more conflicts are detected than were declared by the user, code generation
     * is aborted.
     *
     * @param act_table    the actionPart table to put entries in.
     * @param reduce_table the reduce-goto table to put entries in.
     */
    public void BuildTableEntries(ParseActionTable actTable, ParseReduceTable reduceTable) /*throws internal_error*/ {
        var conflict_set = new VtSet();

        /* pull @out our rows from the tables */
        var our_act_row = actTable.under_state[Index];
        var our_reduce_row = reduceTable.under_state[Index];

        /* consider each item in our state */
        foreach (var item in this.ItemSet) {
            /* if its completed (dot at end) then reduce under the lookahead */
            if (item.dotAtEnd) {
                var reduceAction = new ReduceAction(item.ProductionDraft);

                /* consider each lookahead SymbolDraft */
                for (int termIndex = 0; termIndex < Vt.Count; termIndex++) {
                    /* skip over the ones not in the lookahead */
                    if (!item.LookAheads.contains(termIndex)) { continue; }

                    /* if we don't already have an actionPart put this one in */
                    if (our_act_row.parseActions[termIndex].Kind == ParseAction.ERROR) {
                        our_act_row.parseActions[termIndex] = reduceAction;
                    }
                    else {
                        /* we now have at least one conflict */
                        Vt term = Vt.Find(termIndex);
                        var other_act = our_act_row.parseActions[termIndex];

                        /* if the other act was not a Shift */
                        if ((other_act.Kind != ParseAction.SHIFT) && (other_act.Kind != ParseAction.NONASSOC)) {
                            /* if we have lower index hence priority, replace it */
                            if (item.ProductionDraft.Index < ((ReduceAction)other_act).ReduceWith.Index) {
                                /* replace the actionPart */
                                our_act_row.parseActions[termIndex] = reduceAction;
                            }
                        }
                        else {
                            /* Check precedences,see if problem is correctable */
                            if (FixWithPrecedence(item.ProductionDraft, termIndex, our_act_row, reduceAction)) {
                                term = null;
                            }
                        }
                        if (term != null) {

                            conflict_set.Add(term);
                        }
                    }
                }
            }
        }

        /* consider each EmitSymbols transition */
        for (LALRTransition trans = Transition; trans != null; trans = trans.Next) {
            /* if its on an Vt_ TryAdd a Shift entry */
            var sym = trans.onSymbol;
            if (!sym.IsVn) {
                var act = new ShiftAction(trans.toState);

                /* if we don't already have an actionPart put this one in */
                if (our_act_row.parseActions[sym.Index].Kind == ParseAction.ERROR) {
                    our_act_row.parseActions[sym.Index] = act;
                }
                else {
                    /* we now have at least one conflict */
                    ProductionDraft p = ((ReduceAction)our_act_row.parseActions[sym.Index]).ReduceWith;

                    /* Shift always wins */
                    if (!FixWithPrecedence(p, sym.Index, our_act_row, act)) {
                        our_act_row.parseActions[sym.Index] = act;
                        conflict_set.Add(Vt.Find(sym.Index));
                    }
                }
            }
            else {
                /* for non terminals TryAdd an entry to the reduce-goto table */
                our_reduce_row.under_non_term[sym.Index] = trans.toState;
            }
        }

        /* if we end up with conflict(s), report them */
        if (!conflict_set.empty())
            ReportConflicts(conflict_set);
    }

    /* . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . */

    /**
     * Procedure that attempts to fix a Shift/reduce error by using precedences.
     * --frankf 6/26/96
     * 
     * if a production (also called rule) or the lookahead Vt_ has a
     * precedence, then the table can be fixed. if the rule has greater precedence
     * than the Vt_, a reduce by that rule in inserted in the table. If the
     * Vt_ has a higher precedence, it is shifted. if they have equal
     * precedence, then the associativity of the precedence is used to determine
     * what to put in the table: if the precedence is _left associative, the actionPart
     * is to reduce. if the precedence is _right associative, the actionPart is to Shift.
     * if the precedence is non associative, then it is a syntax error.
     *
     * @param productionDraft                the production
     * @param term_index       the index of the lokahead Vt_
     * @param parse_action_row a row of the actionPart table
     * @param act              the rule in conflict with the table entry
     */

    public bool FixWithPrecedence(ProductionDraft productionDraft, int termIndex, ParseActionRow tableRow, ParseAction act) {
        Vt Vt_ = Vt.Find(termIndex);

        /* if the production has a precedence Count, it can be fixed */
        if (productionDraft.precedenceNum > Associativity.noPrec) {
            /* if production precedes Vt_, put reduce in table */
            if (productionDraft.precedenceNum > Vt_.PrecedenceNum) {
                tableRow.parseActions[termIndex] = InsertReduce(tableRow.parseActions[termIndex], act);
                return true;
            }
            /* if Vt_ precedes rule, put Shift in table */
            else if (productionDraft.precedenceNum < Vt_.PrecedenceNum) {
                tableRow.parseActions[termIndex] = InsertShift(tableRow.parseActions[termIndex], act);
                return true;
            }
            else { /* they are == precedence */
                /* equal precedences have equal sides, so only need to look at one: if it is
                 * _right, put Shift in table */
                if (Vt_.PrecedenceSide == Associativity.right) {
                    tableRow.parseActions[termIndex] = InsertShift(tableRow.parseActions[termIndex], act);
                    return true;
                }
                /* if it is _left, put reduce in table */
                else if (Vt_.PrecedenceSide == Associativity.left) {
                    tableRow.parseActions[termIndex] = InsertReduce(tableRow.parseActions[termIndex], act);
                    return true;
                }
                /* if it is nonassoc, we're not allowed to have two nonassocs of equal
                 * precedence in a row, so put in NONASSOC */
                else if (Vt_.PrecedenceSide == Associativity.nonassoc) {
                    tableRow.parseActions[termIndex] = new NonassocAction();
                    return true;
                }
                else { /* something really went wrong */
                    throw new InternalError("Unable to resolve conflict correctly");
                }
            }
        }
        /* check if Vt_ has precedence, if so, Shift, since rule does not have precedence */
        else if (Vt_.PrecedenceNum > Associativity.noPrec) {
            tableRow.parseActions[termIndex] = InsertShift(tableRow.parseActions[termIndex], act);
            return true;
        }

        /*
         * otherwise, neither the rule nor the Vt_ has a precedence, so it can't be
         * fixed.
         */
        return false;
    }

    /* . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . */

    /*
     * given two actions, and an actionPart type, return the actionPart of that actionPart type.
     * give an error if they are of the same actionPart, because that should never have
     * tried to be fixed
     * 
     */
    public ParseAction InsertAction(ParseAction a1, ParseAction a2, int actType) /*throws internal_error*/ {
        if ((a1.Kind == actType) && (a2.Kind == actType)) {
            throw new InternalError("Conflict resolution of bogus actions");
        }
        else if (a1.Kind == actType) {
            return a1;
        }
        else if (a2.Kind == actType) {
            return a2;
        }
        else {
            throw new InternalError("Conflict resolution of bogus actions");
        }
    }

    /* find the Shift in the two actions */
    public ParseAction InsertShift(ParseAction a1, ParseAction a2) /*throws internal_error*/ {
        return InsertAction(a1, a2, ParseAction.SHIFT);
    }

    /* find the reduce in the two actions */
    public ParseAction InsertReduce(ParseAction a1, ParseAction a2) /*throws internal_error*/ {
        return InsertAction(a1, a2, ParseAction.REDUCE);
    }

    /* . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . */

    /** Produce warning messages for AllVns conflicts found in this state. */
    public void ReportConflicts(VtSet conflictSet) /*throws internal_error*/ {
        bool after_itm;

        /* consider each element */
        foreach (var itm in ItemSet) {
            /* clear the S/R conflict set for this item */

            /* if it results in a reduce, it could be a conflict */
            if (itm.dotAtEnd) {
                /* not yet after item */
                after_itm = false;

                /* compare this item against AllVns others looking for conflicts */
                foreach (var compare in ItemSet) {
                    /* if this is the item, next one is after it */
                    if (itm == compare)
                        after_itm = true;

                    /* only look at it if its not the same item */
                    if (itm != compare) {
                        /* is it a reduce */
                        if (compare.dotAtEnd) {
                            /* only look at reduces after item */
                            if (after_itm)
                                /* does the comparison item conflict? */
                                if (compare.LookAheads.intersects(itm.LookAheads))
                                    /* report a reduce/reduce conflict */
                                    ReportReduceReduce(itm, compare);
                        }
                    }
                }
                /* report S/R conflicts under AllVns the EmitSymbols we conflict under */
                VtSet lookahead = itm.LookAheads;
                for (int t = 0; t < Vt.Count; t++)
                    if (conflictSet.contains(t) && lookahead.contains(t))
                        ReportShiftReduce(itm, t);
            }
        }
    }

    /* . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . */

    /**
     * Produce a warning message for one reduce/reduce conflict.
     *
     * @param itm1 first item in conflict.
     * @param itm2 second item in conflict.
     */
    public void ReportReduceReduce(LALRItem itm1, LALRItem itm2) /*throws internal_error*/ {
        bool comma_flag = false;

        String message = "*** Reduce/Reduce conflict found in state #" + Index + "\n" + "  between "
            + itm1.toSimpleString() + "\n" + "  and     " + itm2.toSimpleString() + "\n" + "  under EmitSymbols: {";
        for (int t = 0; t < Vt.Count; t++) {
            if (itm1.LookAheads.contains(t) && itm2.LookAheads.contains(t)) {
                if (comma_flag)
                    message += (", ");
                else
                    comma_flag = true;
                message += (Vt.Find(t).Name);
            }
        }
        message += "}\n  Resolved in favor of ";
        if (itm1.ProductionDraft.Index < itm2.ProductionDraft.Index)
            message += "the first production.\n";
        else
            message += "the second production.\n";

        /* count the conflict */
        Emit.num_conflicts++;
        ErrorManager.instance.emitWarning(message);
    }

    /* . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . */

    /**
     * Produce a warning message for one Shift/reduce conflict.
     *
     * @param red_itm      the item with the reduce.
     * @param conflict_sym the index of the SymbolDraft conflict occurs under.
     */
    public void ReportShiftReduce(LALRItem redItm, int conflictSym) /*throws internal_error*/ {
        SymbolDraft shift_sym;

        /* emit Peek part of message including the reduce item */
        String message = "*** Shift/Reduce conflict found in state #" + Index + "\n" + "  between "
            + redItm.toSimpleString() + "\n";

        int relevancecounter = 0;
        /* find and report on AllVns ItemSet that Shift under our conflict SymbolDraft */
        foreach (var itm in ItemSet) {

            /* only look if its not the same item and not a reduce */
            if (itm != redItm && !itm.dotAtEnd) {

                /* is it a Shift on our conflicting Vt_ */
                shift_sym = itm.SymbolAfterDot;
                if (!shift_sym.IsVn && shift_sym.Index == conflictSym) {
                    relevancecounter++;
                    /* yes, report on it */
                    message += "  and     " + itm.toSimpleString() + "\n";
                }
            }
        }
        message += "  under SymbolDraft " + Vt.Find(conflictSym).Name + "\n" + "  Resolved in favor of shifting.\n";
        if (relevancecounter == 0)
            return;
        /* count the conflict */
        Emit.num_conflicts++;
        ErrorManager.instance.emitWarning(message);
    }

    /* . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . */

    /** Equality comparison. */
    public bool equals(LALRState other) {
        /* we are equal if our item sets are equal */
        return other != null && this.ItemSet.Equals(other.ItemSet);
    }

    /* . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . */

    /** Generic equality comparison. */
    /*@Override*/
    public override bool Equals(Object? other) {
        if (!(other is LALRState))
            return false;
        else
            return equals((LALRState)other);
    }

    /* . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . */

    /** Produce a hash code. */
    /*@Override*/
    public override int GetHashCode() {
        /* just use the item set hash code */
        return ItemSet.GetHashCode();
    }

    /* . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . */

    /** Convert to a string. */
    /*@Override*/
    public override string ToString() {
        String result;
        LALRTransition tr;

        /* dump the item set */
        result = "LALRState [" + Index + "]: " + _itemSet + "\n";

        /* do the transitions */
        for (tr = Transition; tr != null; tr = tr.Next) {
            result += tr;
            result += "\n";
        }

        return result;
    }

    /*-----------------------------------------------------------*/
}
